package com.demo.loadbalancer;

import io.fabric8.kubernetes.api.model.Service;
import io.fabric8.kubernetes.client.KubernetesClient;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
import org.springframework.cloud.kubernetes.commons.loadbalancer.KubernetesServicesListSupplier;
import org.springframework.cloud.kubernetes.fabric8.loadbalancer.Fabric8ServiceInstanceMapper;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import reactor.core.publisher.Flux;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author 刘斌华
 * @date 2021年10月17日
 * @since 1.0.0
 */
public class VersionedServicesListSupplier extends KubernetesServicesListSupplier {
    
    private static final String HTTP_HEADER_VERSION = "X-Demo-Version";
    
    private static final String METADATA_VERSION = "version";
    
    private final KubernetesClient kubernetesClient;
    
    public VersionedServicesListSupplier(Environment environment, KubernetesClient kubernetesClient,
                                         Fabric8ServiceInstanceMapper mapper, KubernetesDiscoveryProperties discoveryProperties) {
        super(environment, mapper, discoveryProperties);
        this.kubernetesClient = kubernetesClient;
    }
    
    @Override
    @SuppressWarnings("unchecked")
    public Flux<List<ServiceInstance>> get() {
        
        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        String version = request.getHeader(HTTP_HEADER_VERSION);
        
        List<ServiceInstance> allInstances = new ArrayList<>();
        List<ServiceInstance> versionedInstances = new ArrayList<>();
        if (discoveryProperties.isAllNamespaces()) {
            List<Service> services = this.kubernetesClient.services().inAnyNamespace()
                    .withField("metadata.name", getServiceId())
                    .list().getItems();
            services.forEach(service -> {
                ServiceInstance instance = mapper.map(service);
                allInstances.add(instance);
                if (Objects.equals(service.getMetadata().getAdditionalProperties().get(METADATA_VERSION), version)) {
                    versionedInstances.add(instance);
                }
            });
        } else {
            Service service = StringUtils.hasText(this.kubernetesClient.getNamespace())
                    ? this.kubernetesClient.services().inNamespace(this.kubernetesClient.getNamespace())
                    .withName( getServiceId()).get()
                    : this.kubernetesClient.services().withName( getServiceId()).get();
            if (service != null) {
                ServiceInstance instance = mapper.map(service);
                allInstances.add(instance);
                if (Objects.equals(service.getMetadata().getAdditionalProperties().get(METADATA_VERSION), version)) {
                    versionedInstances.add(instance);
                }
            }
        }
        
        return Flux.defer(() -> Flux.just(versionedInstances.isEmpty() ? allInstances : versionedInstances));
        
    }
    
}
